// (c) 2007 Messaging Logic. All Rights Reserved.
package org.xi8ix.loader;

import org.mortbay.jetty.handler.ContextHandler;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.mortbay.jetty.webapp.WebAppContext;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.HandlerContainer;
import org.mortbay.component.AbstractLifeCycle;
import org.mortbay.util.URIUtil;
import org.mortbay.resource.Resource;

import java.util.ArrayList;
import java.util.EventListener;

/**
 * @author Iain Shigeoka
 */
public class PluginDeployer extends AbstractLifeCycle {

    private HandlerContainer contexts;
    private String webAppDir;
    private ArrayList<ContextHandler> deployed;
    private boolean extract;
    private boolean parentLoaderPriority;
    private boolean allowDuplicates;
    private String defaultsDescriptor;

    public HandlerContainer getContexts() {
        return contexts;
    }

    public void setContexts(HandlerContainer contexts) {
        this.contexts = contexts;
    }

    public String getWebAppDir() {
        return webAppDir;
    }

    public void setWebAppDir(String webAppDir) {
        this.webAppDir = webAppDir;
    }

    public ArrayList<ContextHandler> getDeployed() {
        return deployed;
    }

    public void setDeployed(ArrayList<ContextHandler> deployed) {
        this.deployed = deployed;
    }

    public boolean isExtract() {
        return extract;
    }

    public void setExtract(boolean extract) {
        this.extract = extract;
    }

    public boolean isParentLoaderPriority() {
        return parentLoaderPriority;
    }

    public void setParentLoaderPriority(boolean parentLoaderPriority) {
        this.parentLoaderPriority = parentLoaderPriority;
    }

    public boolean isAllowDuplicates() {
        return allowDuplicates;
    }

    public void setAllowDuplicates(boolean allowDuplicates) {
        this.allowDuplicates = allowDuplicates;
    }

    public String getDefaultsDescriptor() {
        return defaultsDescriptor;
    }

    public void setDefaultsDescriptor(String defaultsDescriptor) {
        this.defaultsDescriptor = defaultsDescriptor;
    }

    /**
     * Scan for webapplications.
     *
     * @throws Exception if there was a problem scanning for plugins
     */
    public void scan() throws Exception {
        if (contexts == null)
            throw new IllegalArgumentException("No HandlerContainer");

        Resource r = Resource.newResource(webAppDir);
        if (!r.exists())
            throw new IllegalArgumentException("No such webapps resource " + r);

        if (!r.isDirectory())
            throw new IllegalArgumentException("Not directory webapps resource " + r);

        String[] files = r.list();

        files:
        for (int f = 0; files != null && f < files.length; f++) {
            String context = files[f];

            if (context.equalsIgnoreCase("CVS/") || context.equalsIgnoreCase("CVS") || context.startsWith("."))
                continue;

            Resource app = r.addPath(r.encode(context));

            if (context.toLowerCase().endsWith(".war") || context.toLowerCase().endsWith(".jar") || context.toLowerCase().endsWith(".plugin")) {
                context = context.substring(0, context.length() - 4);
                Resource unpacked = r.addPath(context);
                if (unpacked != null && unpacked.exists() && unpacked.isDirectory())
                    continue;
            } else if (!app.isDirectory())
                continue;

            if (context.equalsIgnoreCase("root") || context.equalsIgnoreCase("root/"))
                context = URIUtil.SLASH;
            else
                context = "/" + context;
            if (context.endsWith("/") && context.length() > 0)
                context = context.substring(0, context.length() - 1);

            // Check the context path has not already been added or the webapp itself is not already deployed
            if (!allowDuplicates) {
                Handler[] installed = contexts.getChildHandlersByClass(ContextHandler.class);
                for (Handler anInstalled : installed) {
                    ContextHandler c = (ContextHandler) anInstalled;

                    if (context.equals(c.getContextPath()))
                        continue files;

                    String path;
                    if (c instanceof WebAppContext)
                        path = ((WebAppContext) c).getWar();
                    else
                        path = (c.getBaseResource() == null ? "" : c.getBaseResource().getFile().getAbsolutePath());

                    if (path.equals(app.getFile().getAbsolutePath()))
                        continue files;

                }
            }

            // create a webapp
            WebAppContext wah;
            if (contexts instanceof ContextHandlerCollection &&
                    WebAppContext.class.isAssignableFrom(((ContextHandlerCollection) contexts).getContextClass())) {
                try {
                    wah = (WebAppContext) ((ContextHandlerCollection) contexts).getContextClass().newInstance();
                }
                catch (Exception e) {
                    throw new Error(e);
                }
            } else {
                wah = new WebAppContext();
            }

            // configure it
            wah.setContextPath(context);
            if (defaultsDescriptor != null)
                wah.setDefaultsDescriptor(defaultsDescriptor);
            wah.setExtractWAR(extract);
            wah.setWar(app.toString());
            wah.setParentLoaderPriority(parentLoaderPriority);

            wah.setEventListeners(new EventListener[]{new ContextListener()});
            // add it
            contexts.addHandler(wah);
            deployed.add(wah);

            if (contexts.isStarted())
                contexts.start();  // TODO Multi exception
        }
    }

     /**
      * @throws Exception
      */
     public void doStart() throws Exception
     {
         deployed = new ArrayList<ContextHandler>();

         scan();

     }

    public void doStop() throws Exception {
        for (int i = deployed.size(); i-- > 0;) {
            ContextHandler wac = deployed.get(i);
            wac.stop();// TODO Multi exception
        }
    }
}
